﻿using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using ControleRepresentante.Logic;
using ControleRepresentante.Logic.Models;
using Telerik.Web.Mvc.UI.Fluent;
using WebSite.Controllers;
using WebSite.ViewModels.Fields;
using WebSite.ViewModels.ViewModelExtensions.IndexViewModelExtensions;

namespace WebSite.ViewModels.IndexViewModels
{
    public abstract class IndexViewModel : IIndexViewModel
    {
        public const string AttributeKey = "ATTRIBUTE";
        public const string HiddenKey = "HIDDEN";

        public bool CanEdit { get; set; }
        public bool CanDelete { get; set; }
        public bool CanPrint { get; set; }
        public IIndexViewModelExtension[] IndexViewModelExtensions { get; set; }
        public string ControllerName { get; set; }
        public IEnumerable<ModelBase> Models { get; set; }
        public bool CanCreate { get; set; }
        public int ModelCount { get; set; }
        public int PageSize { get; set; }
        public IIndexColumnsProvider IndexColumnsProvider { get; set; }
        public RepresentanteInfo RepresentanteInfo { get; set; }

        public string Title { get; set; }

        public RouteValueDictionary GetRouteValues(HttpRequestBase request)
        {
            RouteValueDictionary values = new RouteValueDictionary();
            foreach (string key in request.Form.AllKeys)
            {
                values.Add(key, request.Form[key]);
            }
            foreach (string key in request.QueryString.AllKeys)
            {
                values.Add(key, request.QueryString[key]);
            }
            return values;
        }

        protected IndexViewModel(string title)
        {
            Title = title;
        }

        protected virtual IEnumerable<ButtonType> ButtonTypes(ModelBase modelBase)
        {
            if (CanEdit && CanEditSpecific(modelBase)) yield return ButtonType.Edit;
            if (CanDelete && CanDeleteSpecific(modelBase)) yield return ButtonType.Delete;
        }

        public FormLayoutViewModel GetSearchFormLayoutViewModel(HtmlHelper htmlHelper)
        {
            IEnumerable<IField> searchFields = GetSearchFields();
            return searchFields.Any()
                ? new FormLayoutViewModel(htmlHelper).AddFieldRange(searchFields) 
                : null;
        }

        public abstract FormLayoutViewModel GetFieldsFormLayoutViewModel(HtmlHelper htmlHelper);

        protected virtual bool CanEditSpecific(ModelBase modelBase)
        {
            return IndexViewModelExtensions == null || !IndexViewModelExtensions.Any() || IndexViewModelExtensions.All(x => x.CanEditSpecific(modelBase));
        }

        protected virtual bool CanDeleteSpecific(ModelBase modelBase)
        {
            return IndexViewModelExtensions == null || !IndexViewModelExtensions.Any() || IndexViewModelExtensions.All(x => x.CanDeleteSpecific(modelBase));
        }

        public void IndexColumns(GridColumnFactory<ModelBase> configurator, HtmlHelper htmlHelper)
        {
            IndexColumnDefinitionsCollection indexColumnDefinitionsCollection = GetIndexColumnDefinitions();
            indexColumnDefinitionsCollection.Execute(IndexColumnsProvider.GetIndexColumns(), configurator, htmlHelper);
        }

        public IndexColumnDefinitionsCollection GetIndexColumnDefinitions()
        {
            IndexColumnDefinitionsCollection indexColumnDefinitionsCollection = new IndexColumnDefinitionsCollection();
            RegisterColumns(indexColumnDefinitionsCollection);
            return indexColumnDefinitionsCollection;
        }

        protected void RegisterColumns(IndexColumnDefinitionsCollection indexColumnDefinitionsCollection)
        {
            DoRegisterColumns(indexColumnDefinitionsCollection);
            if (IndexViewModelExtensions != null)
            {
                foreach (IIndexViewModelExtension indexViewModelExtension in IndexViewModelExtensions)
                {
                    indexViewModelExtension.RegisterColumns(indexColumnDefinitionsCollection, IndexColumnsProvider);
                }
            }
        }

        protected abstract void DoRegisterColumns(IndexColumnDefinitionsCollection indexColumnDefinitionsCollection);

        protected virtual IEnumerable<IField> GetSearchFields()
        {
            return IndexViewModelExtensions.SelectMany(x => x.GetSearchFields());
        }

        public IndexGridButtonsViewModel GetIndexGridButtonsViewModel(ModelBase modelBase)
        {
            return new IndexGridButtonsViewModel(ButtonTypes(modelBase), modelBase);
        }

        public RouteValueDictionary GetSearchRouteValueDictionary()
        {
            return new RouteValueDictionary(GetSearchFields().ToDictionary(
                x => x.Name,
                x => x.Value));
        }

        public TabsViewModel GetExtraTabs(HtmlHelper htmlHelper)
        {
            return new TabsViewModel(htmlHelper, ControllerName)
                .AddRange(GetTabs(htmlHelper))
                .AddRange(IndexViewModelExtensions.SelectMany(x => x.GetTabs(htmlHelper)));
        }

        protected virtual IEnumerable<TabItem> GetTabs(HtmlHelper htmlHelper)
        {
            return new TabItem[0];
        }
    }

    public abstract class IndexViewModel<TModel> : IndexViewModel
        where TModel : ModelBase
    {
        protected IndexViewModel(string title) 
            : base(title)
        {
        }

        public sealed override FormLayoutViewModel GetFieldsFormLayoutViewModel(HtmlHelper htmlHelper)
        {
            IndexColumnDefinitionsCollection indexColumnDefinitionsCollection = new IndexColumnDefinitionsCollection();
            RegisterColumns(indexColumnDefinitionsCollection);

            List<CheckBoxField> checkBoxFields = new List<CheckBoxField>();
            IEnumerable<IndexColumn> checkedIndexColumns = IndexColumnsProvider.GetIndexColumns();
            IEnumerable<BuiltInIndexColumn> checkedBuiltInIndexColumns = checkedIndexColumns.OfType<BuiltInIndexColumn>();
            IEnumerable<AttributeIndexColumn> checkedAttributeIndexColumn = checkedIndexColumns.OfType<AttributeIndexColumn>();
            foreach (IndexColumn indexColumn in IndexColumnsProvider.GetAllIndexColumns())
            {
                if (indexColumnDefinitionsCollection.ShouldShow(indexColumn))
                {
                    BuiltInIndexColumn builtInIndexColumn = indexColumn as BuiltInIndexColumn;
                    AttributeIndexColumn attributeIndexColumn = indexColumn as AttributeIndexColumn;
                    if (builtInIndexColumn != null)
                    {
                        bool isChecked = indexColumn.IsMandatory || checkedBuiltInIndexColumns.Any(x => x.Id == builtInIndexColumn.Id);
                        checkBoxFields.Add(new CheckBoxField(builtInIndexColumn.Description, builtInIndexColumn.Id.ToString(), isChecked, !indexColumn.IsMandatory));
                    }
                    else if (attributeIndexColumn != null)
                    {
                        bool isChecked = indexColumn.IsMandatory || checkedAttributeIndexColumn.Any(x => x.Attribute.Id == attributeIndexColumn.Attribute.Id);
                        checkBoxFields.Add(new CheckBoxField(attributeIndexColumn.Attribute.Name, AttributeKey + attributeIndexColumn.Attribute.Id, isChecked, !indexColumn.IsMandatory));
                    }
                }
            }
            return new FormLayoutViewModel(htmlHelper).AddFieldRange(checkBoxFields.OrderBy(x => x.Caption));
        }

        protected sealed override IEnumerable<ButtonType> ButtonTypes(ModelBase modelBase)
        {
            List<ButtonType> buttonTypes = base.ButtonTypes(modelBase).ToList();
            buttonTypes.AddRange(ButtonTypes((TModel)modelBase));
            return buttonTypes;
        }

        protected sealed override bool CanDeleteSpecific(ModelBase modelBase)
        {
            return base.CanDeleteSpecific(modelBase) && CanDeleteSpecific((TModel)modelBase);
        }

        protected sealed override bool CanEditSpecific(ModelBase modelBase)
        {
            return base.CanEditSpecific(modelBase) && CanEditSpecific((TModel)modelBase);
        }

        protected sealed override void DoRegisterColumns(IndexColumnDefinitionsCollection indexColumnDefinitionsCollection)
        {
            RegisterColumns(new IndexColumnDefinitionsCollectionWrapper<TModel>(indexColumnDefinitionsCollection, IndexColumnsProvider));
        }

        protected abstract void RegisterColumns(IndexColumnDefinitionsCollectionWrapper<TModel> indexColumnDefinitionsCollectionWrapper);

        protected virtual bool CanEditSpecific(TModel modelBase)
        {
            return true;
        }

        protected virtual bool CanDeleteSpecific(TModel modelBase)
        {
            return true;
        }

        protected virtual IEnumerable<ButtonType> ButtonTypes(TModel modelBase)
        {
            return new ButtonType[0];
        }
    }
}